﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using MyFloridaHouse.libSvOpenDistricts.Districts;
using MyFloridaHouse.libSvUtilities.Logging;

namespace MyFloridaHouse.libSvOpenDistricts.Census
{
    public partial class CensusGeometry
    {


        public bool BypassLoadWithCensusBlocks(List<DistrictToCensusIDStruct> districtCensusIDList, int districtCount )
        {
            return BypassLoadWithUogIDBlocks(ConvertDistrictCensusIDListToUogID(districtCensusIDList), districtCount);
        }

        public List<DistrictToUogIDStruct> ConvertDistrictCensusIDListToUogID(List<DistrictToCensusIDStruct> districtCensusIDList)
        {
            // join the incoming districtCensusIDList with our census geomtry list to convert censusID's to uogID's which can be used as an index into the Census node list
            return (from node in censusGeometryNodeList
                    join assignment in districtCensusIDList on node.doj00 equals assignment.censusID
                    select new DistrictToUogIDStruct(assignment.districtID, node.uogID, node.uogType)).ToList();
        }

        public bool IsDistrictUogIDListBlocksOnly(List<DistrictToUogIDStruct> districtUogIDList)
        {
            return ((from node in districtUogIDList
                     where node.uogType != CensusGeometryConstants.censusBlockUogType
                     select node).Count() == 0);
        }

        public bool IsDistrictUogIDListValidDistricts(List<DistrictToUogIDStruct> districtUogIDList, int districtCount)
        {
            return ((from node in districtUogIDList
                     where ((node.districtID < 0) | (node.districtID > districtCount))
                     select node).Count() > 0);
        }

        public List<int> convertIntUogIDListToBlocksOnly(List<int> uogIDList)
        {
            List<int> blockOnlyUogIDList = new List<int>();
            foreach (var uogID in uogIDList)
            {
                List<int> subUogIDList = GetUogIDBlocks(uogID);
                foreach (var subUogID in subUogIDList)
                {
                    blockOnlyUogIDList.Add(subUogID);
                }
            }
            return blockOnlyUogIDList;
        }

        private List<int> GetUogIDBlocks(int uogID)
        {
            List<int> uogIDChildBlockIDList = new List<int>();
            if (censusGeometryNodeList[uogID].childNodeList.Count == 0)
            {
                uogIDChildBlockIDList.Add(uogID);
            }
            else
            {
                foreach (var childUogID in censusGeometryNodeList[uogID].childNodeList)
                {
                    uogIDChildBlockIDList.AddRange(GetUogIDBlocks(childUogID.uogID));
                }
            }
            return uogIDChildBlockIDList;
        }




        public bool BypassLoadWithUogIDBlocks(List<DistrictToUogIDStruct> districtUogIDList, int districtCount)
        {
            if (districtUogIDList == null)
            {
                Log.HandleInternalError("There was an unspecified error reading the file.  Sorry, don't have any more information than that.");
                return false;
            }
            else
            {
                if (IsDistrictUogIDListValidDistricts(districtUogIDList, districtCount))
                {
                    int maxDistrictID = (from node in districtUogIDList
                                         select node.districtID).Max();

                    Log.HandleInternalError("You said there where " + districtCount.ToString() + " districts, but the highest districtID in the file is " + maxDistrictID.ToString());
                    return false;
                }
                else
                {
                ResetAllNodesForBypassLoad();

                if (!IsDistrictUogIDListBlocksOnly(districtUogIDList))
                {
                    Log.HandleInternalError("You tried to load Census block data with list of census ID's that are NOT all census blocks");
                    return false;
                }
                else
                {

                    foreach (var assignment in districtUogIDList)
                    {
                        censusGeometryNodeList[assignment.uogID].districtID = assignment.districtID;
                    }

                    UpdateNodeListAfterBypass(CensusGeometryConstants.censusBlockUogType);
                    CheckPlanComplete();
                    return true;
                }
                }
            }

        }

        public void ResetAllNodesForBypassLoad()
        {
            // bypass load means we'll skip the usual walking of the tree up and down.  Special processing will be done after to make sure parent/child district assignments are consistent.

            // set all it's base blocks to the unassigned district ('0')
            // higher level nodes will default to multiDistrict and will be set correctly later
            foreach (var node in censusGeometryNodeList)
            {
                if (node.uogType == CensusGeometryConstants.censusBlockUogType)
                {
                    node.districtID = 0;
                }
                else
                {
                    node.districtID = CensusGeometryConstants.multiDistrictID;
                }

            }
        }

        // IMPORTANT: Call Check Plan Complete after calling this function.  This is recursive, so don't want to put it here
        public void UpdateNodeListAfterBypass(int nodeType)
        {
            //process the node list from the bottom up, assigning either the correct district or multi district
            // NOTE: THis assumes node types for building layers start at zero for blocks and work their way up
            nodeType = nodeType + 1;
            var parentNodeTypeQuery = from node in censusGeometryNodeList
                                      where node.uogType == nodeType
                                      select node;
            foreach (var parentNode in parentNodeTypeQuery)
            {
                censusGeometryNodeList[parentNode.uogID].districtID = GetCensusNodeChildrenDistricts(parentNode.uogID).allChildrenDistrictID;
            }
            if (parentNodeTypeQuery.Count() > 0)
            {
                UpdateNodeListAfterBypass(nodeType);
            }

        }
    }
}
